#import <Foundation/Foundation.h>
#include "/usr/local/include/dispatch/dispatch.h"

typedef unsigned long long ULL;

typedef struct {
	ULL start;
	ULL end;
}range_t,*prange_t;

bool is_prime(x){
	ULL j = sqrtl(x + 1);
	if(x==2) return true;
	if(x<2 || x%2 == 0) return false;
	for(ULL i = 3;i<=j;i = i+2){
		if(x%i == 0) return false;
	}
	return true;
}

ULL p_count(ULL start,ULL end){
	ULL count = 0;
	for(ULL i = start;i<=end;i++){
		if(is_prime(i)) count++;
	}
	return count;
}

range_t get_range(int index){
	switch(index){
		case 0:
			return (range_t){1,10000};
		case 1:
			return (range_t){10001,20000};
		case 2:
			return (range_t){20001,30000};
		case 3:
			return (range_t){30001,40000};
	}
	return (range_t){-1,-1};
}

static ULL g_count = 0;
static NSNumber *g_lock_count = nil;

void callback(void *context){
	prange_t pr = context;
	NSLog(@"range : (%llu - %llu)",pr->start,pr->end);

	ULL count = p_count(pr->start,pr->end);
	@synchronized(g_lock_count){
		g_count += count;
	}
}

void function_way(void){
	g_lock_count = @1;
	range_t range_ary[4] = {{1,100000},{100001,200000},{200001,300000},{300001,400000}};
	//FIXME:dispatch_queue_create make crash!!!
	dispatch_queue_t queue = dispatch_queue_create("WorkBlocks",NULL);
	//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
	dispatch_group_t group = dispatch_group_create();
///*
	for(int i = 0;i<4;i++){
		dispatch_group_async_f(group,queue,&range_ary[i],callback);
	}

	dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
//*/	
	//dispatch_release(queue);
	NSLog(@"at last! count is %llu",g_count);
}

void apply_way(void){
	dispatch_queue_t queue = dispatch_queue_create("WorkBlocks",NULL);
	ULL __block last_count = 0;
	NSNumber *lock_count = @2;

	dispatch_apply(4,queue,^(size_t i){
		range_t r = get_range(i);
		NSLog(@"IDX:%lu:range is (%llu - %llu)",i,r.start,r.end);
		ULL count = p_count(r.start,r.end);
		@synchronized(lock_count){
			last_count += count;
		}
	});

	NSLog(@"at last! count is %llu",last_count);
}

void group_way(void){
	NSNumber *lock_index = @1;
	NSNumber *lock_count = @2;
	ULL __block last_count = 0;
	int __block work_index = 0;
	//range_t range_ary[4] = {{1,100},{101,200},{201,300},{301,400}};
	//FIXME:dispatch_queue_create make crash!!!
	dispatch_queue_t queue = dispatch_queue_create("WorkBlocks",NULL);
	//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
	dispatch_group_t group = dispatch_group_create();
///*
	dispatch_block_t task = ^(void){
		int index = work_index;
		NSLog(@"my work index is %d",index);
		@synchronized(lock_index){
			++work_index;
		}

		range_t r = get_range(index);
		ULL count = p_count(r.start,r.end);
		@synchronized(lock_count){
			last_count += count;
		}

	};

	for(int i = 0;i<4;i++){
		dispatch_group_async(group,queue,task);
	}

	dispatch_group_wait(group,DISPATCH_TIME_FOREVER);
//*/	
	//dispatch_release(queue);
	NSLog(@"at last! count is %llu",last_count);
}

int main(void){
	@autoreleasepool{
		//group_way();
		//apply_way();
		function_way();
	}
	return 0;
}